package cn.felord.util;

import cn.felord.wepay.common.exception.PayException;
import cn.felord.wepay.common.pay.Decryptable;
import cn.felord.wepay.common.pay.PayConfig;
import cn.felord.wepay.common.pay.Payable;
import cn.felord.wepay.common.pay.PreBusinessService;
import cn.felord.wepay.common.proxy.ProxyPayHandler;
import cn.felord.wepay.common.util.Configuration;
import cn.felord.wepay.wechat.entity.WeChatPayConfig;
import cn.felord.wepay.wechat.service.WeChatPayClient;

/**
 * 获取支付客户端   支付通过此类进行操作
 *
 * @author Dax
 * @version v1.0.0
 * @since 2017 /8/28  17:27
 */


public class ClientUtil {
    private ClientUtil() {
    }

    /**
     * 获取默认配置代理.
     *
     * @param decryptable        实现解密方法    配置参数配置对应加密的方法需要加密配置  如果不实现  可以传null 或者原路返回实现
     * @param preBusinessService 在统一下单前需要处理的支付业务逻辑的实现接口
     * @return the pay proxy   返回默认配置的支付代理  必须有一个配置文件 而且名称必须为weChatConfig.properties
     * @throws PayException the pay exception
     */
    public static Payable getPayProxy(Decryptable decryptable, PreBusinessService preBusinessService) throws PayException {
        Payable payable = getClient(decryptable, Configuration.class);
        ProxyPayHandler proxyPayHandler = new ProxyPayHandler(payable, preBusinessService);
        return proxyPayHandler.initProxy();
    }

    /**
     * 获取自定义配置代理.
     *
     * @param <C>                Configuration 的子类 主要为了动态加载配置  实现 多商户号  支付  参见 @see
     * @param decryptable        实现解密方法    配置参数配置对应加密的方法需要加密配置  如果不实现  可以传null 或者原路返回实现
     * @param preBusinessService 在统一下单前需要处理的支付业务逻辑的实现接口
     * @param clazz               Configuration 的子类的Class 类   目的为了获取注解参数
     * @return the pay proxy         返回指定配置的支付代理
     * @throws PayException the pay exception
     * @see cn.felord.config
     */
    public static <C extends Configuration> Payable getPayProxy(Decryptable decryptable, PreBusinessService preBusinessService, Class<C> clazz) throws PayException {
        Payable payable = getClient(decryptable, clazz);
        ProxyPayHandler proxyPayHandler = new ProxyPayHandler(payable, preBusinessService);
        return proxyPayHandler.initProxy();
    }

    /**
     * Gets client.
     *
     * @param decryptable the decryptable
     * @return the client
     * @throws PayException the pay exception
     */
    public static <C extends Configuration> Payable getClient(Decryptable decryptable, Class<C> clazz) throws PayException {
        PayConfig payConfig = new WeChatPayConfig.Builder(decryptable, clazz).build();
        return new WeChatPayClient(payConfig);
    }
}
